home *** CD-ROM | disk | FTP | other *** search
- AN EXAMPLE OF CONVERTING A PROGRAM WRITTEN FOR MASM INTO ONE WRITTEN FOR A86
- by Eric Isaacson
-
-
- Recently a user sent me the file SETUP.ASM, a program written to assemble
- under Microsoft's MASM assembler. He wanted to know why A86 wouldn't assemble
- it, and why he should choose A86 over MASM, in view of the fact that there are
- hundreds of programs out there written for MASM. This paper is a response to
- that question. In it, I show the minimum alterations necessary to produce an
- A86 source file that assembles to an equivalent functioning program. I go on
- from there, to show how the language extension features of A86 can let you
- make the program simpler and clearer. Finally, I do an extensive reworking of
- the program, rewriting portions of code, renaming variables and procedures,
- and adding more comments. By carefully studying the source program at each
- stage of the transformation process, you'll learn not only about the
- differences between A86 and MASM, but about how to transform an ordinary
- assembly-language program into a well-written one.
-
-
- STEP 1. CONVERTING THE PROGRAM
-
- The program that the user sent me is in the file SETUP.ASM. To make a COM
- program file from this source file using MASM, you must assemble it with MASM,
- link the resulting OBJ file using LINK (ignoring the 1 error message that LINK
- always gives you when you use MASM to create a COM file), feed the resulting
- EXE file to EXE2BIN, and finally rename the resulting BIN file to SETUP.COM.
- The resulting file is 3129 bytes long.
-
- If you attempt to assemble SETUP.ASM using A86 version 3.04, you'll get four
- errors. The first three are all of the same type-- an attempt to MOV a symbol
- into a general register, where the symbol is a segment name defined with a
- SEGMENT AT directive. I corrected this by replacing the SEGMENT AT directives
- (all three are together at the top of the program) with EQU directives,
- EQUated to the AT-value. Similarly, the single symbol defined within each of
- the SEGMENTS was converted to a definition via EQU.
-
- The fourth error is the END BEGIN at the end of the program. Since A86 treats
- this as equivalent to MAIN EQU BEGIN, and since the program already has a
- symbol MAIN defined elsewhere, this was a multiple definition. I corrected
- this simply by deleting the END BEGIN line, since A86 doesn't need the END
- directive.
-
- These modifications took me five minutes to find and make, and I had a program
- that A86 accepted. But the program didn't work. A glance at the code
- contents revealed that interrupt drivers were involved, in which the DS, ES,
- and SS registers didn't have the same values as the CS register. Some of the
- memory accesses needed explicit CS override bytes coded for them, since A86
- doesn't act on ASSUME directives. I scanned through the code and found four
- places where CS overrides were needed. Diagnosing and solving this problem
- took about twenty minutes; so I had a working A86 program within a half hour.
- I would guess this to be worse than average, since most assembly-language COM
- programs don't use multiple-segments the way interrupt drivers do.
-
- *** I have made enhancements so that starting with Version 3.05, my assembler
- will assemble SETUP.ASM without modification. I added interpretation of
- SEGMENT AT to be an EQU of the segment name to the AT value, followed by
- entry into STRUC mode for assembly of declarations within the structure.
- V3.05 also completely ignores the END directive in non-OBJ mode.
-
- The source for the minimal changes I have described is the file S1.8. The
- command A86 S1.8 makes an S1.COM file directly, that is functionally
- equivalent to the SETUP.COM file produced by MASM, LINK, EXE2BIN, and REN.
- The S1.COM file is 3105 bytes long, which is 24 bytes shorter than SETUP.COM.
- The difference comes from 19 unnecessary segment-override bytes produced by
- MASM, plus 5 LEA instructions coded in situations where an equivalent MOV
- instruction would have been more efficient. A86 automatically generates the
- more efficient MOV instruction, and MASM doesn't.
-
-
-
- STEP 2. INTRODUCING A86 LANGUAGE FEATURES THAT DON'T CHANGE THE PROGRAM
-
- Of course, I could have stopped with step 1. But I wanted to explore the
- possibilities for improving the program, so I continued. The next step was to
- add A86 language features, to make the program clearer. The first part of
- this transformation was to eliminate all unnecessary red-tape directives, and
- to replace all the place-marker symbols with A86 local labels (L0 through L9).
- The symbols were easy to find, since the author of the program followed the
- reasonable MASM practice of ending place-marker symbols with digits. Because
- the local names are only two characters long, it becomes reasonable to indent
- instructions by only two spaces, leaving room for longer comments. Next, I
- found places to incorporate A86 language features into individual instruction
- sequences: multiple operands to PUSH POP INC DEC, conditional returns, MOV
- segreg,segreg, and IF cond stmt. The resulting program, S2.8, produces a
- virtually identical 3105-byte COM file to S1.8, but the source code appearance
- is considerably changed for the better.
-
-
- STEP 3. MAKING MINOR CODE OPTIMIZATIONS
-
- Next, I started making changes to improve the code itself. Among the changes:
-
- 1. I renamed many variables and procedures, to make the program easier to
- follow. Same of the renaming was simple unabbreviation: for example,
- VIDEO2MEM to VIDEO_TO_MEM, and PAGE_NO to PAGE_NUMBER. Other renaming
- involved making a completely different, clearer choice of name: for
- example, SETUP_STATUS to WINDOW_ACTIVE?, and MAIN to OUR_HANDLER.
-
- 2. I combined that three original SEGMENT ATs and the variables they contained
- into three DD constants, to be loaded into pointers with LDS or LES
- instructions, followed by indirect memory instructions to access the
- variables.
-
- 3. I rearranged the main interactive loop to make the flow of control clearer.
- The exit-code executed when the ESC key is pressed is separated from the
- main flow, and clearly labelled ESC_SEEN. The rest of the main loop was
- consolidated and arranged to clearly show its loop structure.
-
- 4. I performed code optimizations based on 86 instruction set features the
- original author didn't take advantage of. For example, the sequence
-
- L1:
- MOVSW
- LOOP L1
-
- was replaced by a simple REP MOVSW instruction. The preceding CLD
- instruction was moved to the start of interrupt processing, reducing the
- procedure WRITELN to the single REP MOVSW line. So I eliminated WRITELN
- and replaced the instances of CALL WRITELN with REP MOVSW. I could have
- treated MEM2MEM similarly, except that MEM2MEM is never called so it can be
- eliminated outright. Finally, the sequence
-
- SUB BX,2
- MOV AL,DISPLAY_TABLE[BX]
-
- was replaced by MOV AL,DISPLAY_TABLE[BX-2] .
-
- In addition to the coding changes, I converted all non-comment code to all-
- caps, to complete the conversion of the program to my formatting conventions.
- The resulting program, S3.8, assembles to a 3065-byte COM file, 40 bytes less
- than the previous version due to the optimizations.
-
-
- STEP 4. MAKING MAJOR CODE OPTIMIZATIONS
-
- For the final revision of the program I made major code optimizations:
-
- 1. I completely overhauled the usage of memory variables. Some variables,
- such as ATTRIBUTE1, were eliminated, their values kept in registers. The
- tables VIDEO and DISPLAY_TABLE were replaced by the more directly useful
- ENABLE_VALUE and VIDEO_SEG.
-
- 2. I redesigned the parameterization of VIDEO_TO_MEM and MEM_TO_VIDEO, that
- defines the size and location of the pop-up window. It had previously been
- a run-time parameterization, always called with the same values. I
- introduced a set of EQUs for the parameters, defining the window at
- assembly time. VIDEO_OFFSET was transformed from a run-time procedure to
- an assembly-time expression EQUate. All constant references depending on
- window size were recast in terms of the parameter-symbols. Assertion-
- checking was also introduced to insure that the declaration of the window
- contents contains the proper number of bytes.
-
- 3. The program was rearranged to save space. The buffer used for storing the
- contents of the screen beneath the pop-up window was moved to the start of
- the program, so that the 256-byte PSP buffer could be a part of the storage
- buffer. The initialization code and window source code was moved there
- also, to save space. The buffer containing the constructed window image
- was moved to beyond the area of the COM file, reducing the size of the COM
- file by 1064 bytes in one stroke.
-
- 4. The array CODE_TABLE was converted from fixed-length records to delimited
- variable-length records, saving more program space.
-
- 5. The pushing of all registers except AX was deferred until after the hot-key
- check, to reduce keystroke computational overhead time when the program is
- not in effect.
-
- 6. More changes were made to improve program readability. The installation
- code was broken up into procedures, for clarity. The keycode values FUNC
- and SHIFT_F were declared and used, to make the key-scanning code easier to
- follow. The program itself was renamed to the more descriptive EPSONSET,
- and an explanatory paragraph was added to the top of the source code. The
- instruction-level comments were improved.
-
- The resulting final source program is S4.8, which assembles to a COM file of
- only 1237 bytes, less than 40% of the original program size. I retained the
- original copyright notice, although it might be argued that I transformed the
- program enough to call it my own.
-
-
-